#ifndef __M_DB_H__
#define __M_DB_H__

#include "util.hpp"
#include <cassert>

//为数据库中的user_table表创建类来管理
class user_table{
private:
    MYSQL *_mysql;//mysql操作句柄
    std::mutex _mutex; //互斥锁保护数据库的访问操作

public:
    //初始化mysql操作句柄
    user_table(const std::string &host,
               const std::string &username,
               const std::string &password,
               const std::string &dbname,
               uint16_t port = 3306){
                    _mysql = mysql_util::mysql_create(host,username,password,dbname,port);
                    assert(_mysql != NULL);
               }

    //销毁mysql句柄
    ~user_table(){
        mysql_util::mysql_destroy(_mysql);
        _mysql = NULL;
    }

    //注册时新增用户
    bool insert(Json::Value &user){
#define INSERT_USER "insert user values(null,'%s','%s',1000,0,0);"
        if(user["password"].isNull() || user["username"].isNull()){
            DLOG("INPUT PASSWORD OR USERNAME");
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false){
            DLOG("insert user info failed!!\n");
            return false;
        }
        return true;
    }

    //登录验证时，并返回详细的用户信息
    bool login(Json::Value &user){
        //如果用户信息不存在则返回false
        if(user["password"].isNull() || user["username"].isNull()){
            DLOG("INPUT PASSWORD OR USERNAME");
            return false;
        }
        //以用户名和密码共同作为查询过滤条件，查询到数据则表示用户名密码一致，没有信息则用户名密码错误
#define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password= '%s';"
        char sql[4096] = {0};
        sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());
        MYSQL_RES *res = NULL;//定义一个存储结果的变量
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);
            if(ret == false){
                DLOG("user login failed!!\n");
                return false;
            }
            //要么有数据，要么没有数据，就算有数据也只能有一条数据
            res = mysql_store_result(_mysql);
            if(res == NULL){
                DLOG("have no login user info!!");
                return false;
            }
        }
        //拿到结果之后进行结果条数的获取，和遍历结果集存储到json变量中
        int row_num = mysql_num_rows(res);
        if(row_num != 1){   //用户信息如果大于一条，说明用户不唯一了
            DLOG("the user information queried is not unique!!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);//不要忘记释放result
        return true;
    }

    //通过用户名获取用户信息
    bool select_by_name(const std::string &name,Json::Value &user){
#define USER_BY_NAME "select id,score,total_count,win_count form user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_NAME,name.c_str());//把查询语句整合到sql中
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false) {
                    DLOG("get user by name failed!!\n");
                    return false;
            }
            //按理说要么有数据，要么没有数据，就算有数据也只能有一条数据
            res = mysql_store_result(_mysql);
            if (res == NULL) {
                    DLOG("have no user info!!");
                    return false;
            }
        }
        int row_num = mysql_num_rows(res);
        if (row_num != 1) {
            DLOG("the user information queried is not unique!!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["username"] = name;
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    //通过用户id获取用户信息
    bool select_by_id(uint64_t id, Json::Value &user) {
#define USER_BY_ID "select username, score, total_count, win_count from user where id = %ld;"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_ID, id);
        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false) {
                    DLOG("get user by id failed!!\n");
                    return false;
            }
            //按理说要么有数据，要么没有数据，就算有数据也只能有一条数据
            res = mysql_store_result(_mysql);
            if (res == NULL) {
                    DLOG("have no user info!!");
                    return false;
            }
        }
        int row_num = mysql_num_rows(res);
        if (row_num != 1) {
            DLOG("the user information queried is not unique!!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"] = row[0];
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }

    //胜利时天梯分数增加30分，战斗场次增加1，胜利场次增加1
    bool win(uint64_t id){
#define USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%ld;"
        char sql[4096] = {0};
        sprintf(sql,USER_WIN,id);
        bool ret = mysql_util::mysql_exec(_mysql,sql);
        if(ret == false){
            DLOG("update win user info failed!!\n");
            return false;
        }
        return true;
    }

    //失败时天梯分数减少30，战斗场次增加1，其他不变
    bool lose(uint64_t id){
#define USER_LOSE "update user set score=score-30, total_count=total_count+1 where id=%ld;"
        char sql[4096] = {0};
        sprintf(sql, USER_LOSE, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false) {
            DLOG("update lose user info failed!!\n");
            return false;
        }
        return true;    
    }


};

#endif